import java.util.ArrayList;


public class Server {
	
	String Name;
	
	double CPU;
	double Mem;
	double BW;
	
	double utilization;
	
	ArrayList<VirtualMachine> VMs; 
	
	public Server(String name, double cpu, double mem, double bw){
		
		this.Name = name;
		this.CPU = cpu;
		this.Mem = mem;
		this.BW = bw;
		
		utilization = 0;
		
		VMs = new ArrayList<VirtualMachine>();
		
	}
	
	
	public double getUtilization(){
		
		double CPUUtil = getCPUUtilization();
		double MemUtil = getMemUtilization();
		double BWUtil = getBWUtilization();
		CPUUtil = getCPUUtilization();
		MemUtil = getMemUtilization();
		
		for(VirtualMachine vm: VMs)
			vm.blocked = false;
		
		utilization = (CPUUtil * (100/3)) + (MemUtil * (100/3)) + (BWUtil * (100/3));
		
		return (utilization);
		
	}
	
	
	public double getCPUUtilization(){
		
		double CPULoad = 0.0;
		double CPUUasge = 0.0;
		
		for(VirtualMachine vm: VMs){
			
			if(vm.blocked)
				continue;
			
			CPUUasge = vm.getCPUUsage();
			
			if(CPULoad + CPUUasge > CPU){
				vm.blocked = true;
//				System.out.println("Virtual Machine "+vm.Name+" was blocked due to lack of physical CPU resources.");
			}else
				CPULoad += CPUUasge;
			
		}
		
		return(CPULoad / CPU);
		
	}
	
	public double getMemUtilization(){
		
		double MemLoad = 0.0;
		double MemUsage = 0.0;
		
		for(VirtualMachine vm: VMs){
			
			if(vm.blocked)
				continue;
			
			MemUsage = vm.getMemUsage();
			
			if(MemLoad + MemUsage > Mem){
				vm.blocked = true;
//				System.out.println("Virtual Machine "+vm.Name+" was blocked due to lack of physical Memory resources.");
			}else
				MemLoad += MemUsage;
			
		}
		
		return(MemLoad / Mem);
		
	}
	
	public double getBWUtilization(){
		
		double BWLoad = 0.0;
		double BWUsage = 0.0;
		
		for(VirtualMachine vm: VMs){
			
			if(vm.blocked)
				continue;
			
			BWUsage = vm.getBWUsage();
			
			if(BWLoad + BWUsage > BW){
				vm.blocked = true;
//				System.out.println("Virtual Machine "+vm.Name+" was blocked due to lack of physical Network resources.");
			}else
				BWLoad += BWUsage;
			
		}
		
		return(BWLoad / BW);
		
	}
	
	
	public boolean canBeAdded(VirtualMachine v){
		
		v.blocked = false;
		VMs.add(VMs.size(), v);
		
		getCPUUtilization();
		getMemUtilization();
		getBWUtilization();
		
		VirtualMachine vm = VMs.remove(VMs.size()-1);
		
		for(VirtualMachine x : VMs)
			x.blocked = false;
		
		return(!vm.blocked);
		
	}
	
	
	public void addVM(VirtualMachine vm){
		
		VMs.add(vm);
		vm.setPhysicalServer(this);
		
	}
	
	
	public void randomizeUsage() {
		
		for(VirtualMachine vm : VMs)
			vm.randomizeUsage();
		
	}
	
	
	public String toString(){
		
		String result = "Server Name: "+Name+" , CPU: "+CPU+"GHz , Mem: "+Mem+"GB , BW: "+BW+"Mbps";
		
		return(result);
		
	}

}
